package basic.arch.component.lock.distributed;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;

import basic.arch.component.lock.aop.annotation.Lock;
import basic.arch.component.lock.config.CurrentLockSettings;

public abstract class DistributionLockSupport implements DistributionLock,InitializingBean{
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    
    public static final ThreadLocal<DistributionLockResult> distributionLockResultThreadLocal = new ThreadLocal<DistributionLockResult>();
    
    
    public boolean tryLock(CurrentLockSettings currentLockSettings){
        final String currenLockKey = currentLockSettings.getCurrenLockKey();
        DistributionLockResult distributionLockResult = new DistributionLockResult();
        long start = System.currentTimeMillis();
        long end = 0;
        int maxWaitTime = currentLockSettings.getDistributionLockMaxWaitTime();
        boolean flag = false;
        while (true) {
            try {
                long redisStartTime = System.currentTimeMillis();
                if (acquire(currentLockSettings)) {
                    distributionLockResult.setDistributionLockSuccess(true);
                    long redisEndTime = System.currentTimeMillis();
                    distributionLockResult.setDistributionAccquireLockTime(redisEndTime - redisStartTime);
                    flag = true;
                    break;
                }
            } catch (Exception e) {
                logger.error("key:{},获取分布式锁发生错误,{}", currenLockKey, e);
            }
            end = System.currentTimeMillis();
            if (maxWaitTime > 0 && maxWaitTime < (end - start)) {
                break;
            } else {
                continue;
            }
        }
        end = System.currentTimeMillis();
        distributionLockResult.setDistributionLockWaitTime(end - start);
        distributionLockResultThreadLocal.set(distributionLockResult);
        return flag;
    }
    
    protected abstract boolean acquire(CurrentLockSettings currentLockSettings)  throws Exception;
    
    protected abstract void unlock0(String key);
    
    
    public void unlock(String key){
        try {
            unlock0(key);
        } catch (Exception e) {
            logger.error("key:{},释放分布式锁发生错误,{}", key, e);
        }finally {
            distributionLockResultThreadLocal.remove();
        }
    }
    
    public abstract Lock.DisstributionLockType getType();
    
    @Override
    public void afterPropertiesSet() throws Exception {
    }
    
}
